//
//  YYJ_PublicClass.m
//  miaoxiaqianbao
//
//  Created by Lonely丶晏袁杰 on 2018/10/9.
//  Copyright © 2018年 Lonely`yyj. All rights reserved.
//

#import "YYJ_PublicClass.h"
#import <CommonCrypto/CommonDigest.h>
#import <sys/utsname.h>
#import "ANDA_AlertVCViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AudioUnit/AudioUnit.h>
#import "ANDA_PopUpsViewController.h"
#import "ANDA_SharePage_ViewController.h"
#import "ANDA_SystemInfoDetailViewController.h"
@implementation YYJ_PublicClass
#pragma mark - 计算文字大小
+(CGSize)user_getSize:(UIFont *)font With:(CGFloat)with Hight:(CGFloat)hight String:(NSString *)str{
    return calcTextSizeV2(CGSizeMake(with, hight), str, 0, font);
}
#pragma mark - 获取当前屏幕显示的viewcontroller
+(UIViewController *)getCurrentVC{
//    UIViewController *result = nil;
    
    UIViewController* vc = [UIApplication sharedApplication].keyWindow.rootViewController;
    
    while (1) {
        
        if ([vc isKindOfClass:[UITabBarController class]]) {
            vc = ((UITabBarController*)vc).selectedViewController;
        }
        if ([vc isKindOfClass:[UINavigationController class]]) {
            vc = ((UINavigationController*)vc).visibleViewController;
        }
        if (vc.presentedViewController) {
            vc = vc.presentedViewController;
        }else{
            break;
        }
        
    }
    
    return vc;

}
#pragma mark - 浮现一个弹窗
+(void)showMessage:(NSString *)title{
    if(![title isKindOfClass:[NSString class]]){
        title = @"未知错误";
    }
    UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:nil message:title preferredStyle:UIAlertControllerStyleAlert];
    [alertVc addAction:[UIAlertAction actionWithTitle:Anda_locForKey(@"ANDA.确认") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        if ([title isEqualToString:@"无效的token"]) {
            
        }
    }]];
    //主线程执行
    dispatch_async(dispatch_get_main_queue(), ^{
        [[YYJ_PublicClass getCurrentVC] presentViewController:alertVc animated:YES completion:nil];
    });
}
+(void)showMessage:(NSString *)title inVC:(UIViewController *)kVC{
    UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:nil message:title preferredStyle:UIAlertControllerStyleAlert];
    [alertVc addAction:[UIAlertAction actionWithTitle:Anda_locForKey(@"ANDA.确认") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

    }]];
    [kVC presentViewController:alertVc animated:YES completion:nil];
}
#pragma mark - MD5加密
+(NSString *) md5: (NSString *) inPutText{
    const char *cStr = [inPutText UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
    CC_MD5(cStr, strlen(cStr), result);
#pragma clang diagnostic pop
    return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
             result[0], result[1], result[2], result[3],
             result[4], result[5], result[6], result[7],
             result[8], result[9], result[10], result[11],
             result[12], result[13], result[14], result[15]
             ] lowercaseString];
}
#pragma mark -  /** 设置按钮  图片在上 文字在下 水平居中  */
+(void)buttonTopImageBottomTitle:(UIButton*)btn{
    //使图片和文字水平居中显示
    btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
    btn.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
    //文字距离上边框的距离增加imageView的高度，距离左边框减少imageView的宽度，距离下边框和右边框距离不变
    CGSize imageSize = btn.imageView.frame.size;
    CGSize LabelSize = [YYJ_PublicClass user_getSize:btn.titleLabel.font With:MAXFLOAT Hight:CGRectGetHeight(btn.titleLabel.frame) String:btn.currentTitle];
    CGFloat btnWidth = CGRectGetWidth(btn.frame);
    CGFloat btnHeight = CGRectGetHeight(btn.frame);

    CGFloat xxx = (btnHeight-imageSize.height-LabelSize.height)/3.0f;

    //图片距离右边框距离减少图片的宽度，其它不边

    CGFloat imageTop = xxx;
    CGFloat imageLeft = (btnWidth-imageSize.width)/2.0f;
    [btn setImageEdgeInsets:UIEdgeInsetsMake(imageTop,imageLeft,0.0, 0.0)];


    CGFloat titleTop = imageSize.height + xxx*2;
    CGFloat titleLeft = (btnWidth-LabelSize.width)/2.0f - imageSize.width;
    [btn setTitleEdgeInsets:UIEdgeInsetsMake(titleTop,titleLeft, 0.0,0.0)];

}
#pragma mark - 过滤数据
/**
 * kBaseModel 传入要检测的model
 * containsArray 传入要检测的数组
 * key 传入要检测的数据 key
 */
+(BOOL)containsObject:(YYJ_BaseModel *)kBaseModel
             andArray:(NSMutableArray *)containsArray
            searchKey:(NSString *)key{
    NSString *lowercasePredicateString;
    NSString *kIdString;
    lowercasePredicateString = [key stringByAppendingString:@" == %@"];
    kIdString = [kBaseModel.returnDict objectForKey:key];
    NSPredicate* lowercasePredicate = [NSPredicate predicateWithFormat:lowercasePredicateString,kIdString];
    NSArray * lowercaseTemporary = [containsArray filteredArrayUsingPredicate:lowercasePredicate];
    return lowercaseTemporary.count;
}
#pragma mark - 获得当前 window
+ (UIWindow *)mainWindow
{
    UIApplication *app = [UIApplication sharedApplication];
    if ([app.delegate respondsToSelector:@selector(window)])
    {
        return [app.delegate window];
    }
    else
    {
        return [app keyWindow];
    }
}
#pragma mark - 数据转 Json 字符串
+(NSString *)dataTurnJsonSrting:(id)obj{
    NSData *kJsonData = [NSJSONSerialization dataWithJSONObject:obj options:0 error:nil];
    return [[NSString alloc] initWithData:kJsonData encoding:NSUTF8StringEncoding];
}
#pragma mark - Json 转字典
+(id)dictionaryWithJsonString:(NSString *)jsonString{
    if (jsonString == nil) {
        return nil;
    }
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *err;
    if(err) {
        NSLog(@"json解析失败：%@",err);
        return nil;
    }
    return [NSJSONSerialization JSONObjectWithData:jsonData
                                           options:NSJSONReadingMutableContainers
                                             error:&err];
}
#pragma mark base64转码
+ (NSString *)encode:(NSString *)string
{
    //先将string转换成data
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];

    NSData *base64Data = [data base64EncodedDataWithOptions:0];

    NSString *baseString = [[NSString alloc]initWithData:base64Data encoding:NSUTF8StringEncoding];

    return baseString;
}
#pragma mark base64解码
+ (NSString *)dencode:(NSString *)base64String
{
    //NSData *base64data = [string dataUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [[NSData alloc]initWithBase64EncodedString:base64String options:NSDataBase64DecodingIgnoreUnknownCharacters];

    NSString *string = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];

    return string;
}
#pragma mark - url 中文特殊字符转码
+(NSString *)endodedUrl:(NSString *)urlSring{
    NSString *encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,(CFStringRef)urlSring,(CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]",NULL,kCFStringEncodingUTF8));
    return encodedString;
}
#pragma mark - 返回一个单击手势
+(UITapGestureRecognizer* )getTabGestureRecognizer:(id)target action:(SEL)action{
    //创建一个点击手势
    UITapGestureRecognizer*kTap=[[UITapGestureRecognizer alloc]init];
    //给手势添加事件处理程序
    [kTap addTarget:target action:action];
    //指定点击几下触发响应
    kTap.numberOfTapsRequired=1;
    //指定需要几个手指点击
    kTap.numberOfTouchesRequired=1;
    //给self.view 添加点击手势
    return kTap;
}
#pragma mark - 时间格式
+(NSString *)dateTimeConvert:(NSString *)timestamp andFormat:(NSString *)format{
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:[timestamp doubleValue]];
    //普遍格式
    NSDateFormatter *dateTimeFormat = [[NSDateFormatter alloc] init];
    [dateTimeFormat setDateFormat:format];
    return [dateTimeFormat stringFromDate:date];
}
#pragma mark - 判断手机型号
/**
 * 判断手机型号
 */
+(NSString*)iphoneType {

    //需要导入头文件：#import <sys/utsname.h>
    struct utsname systemInfo;

    uname(&systemInfo);

    NSString*platform = [NSString stringWithCString: systemInfo.machine encoding:NSASCIIStringEncoding];

    if([platform isEqualToString:@"iPhone1,1"])
        return @"iPhone 2G";
    if([platform isEqualToString:@"iPhone1,2"])
        return @"iPhone 3G";
    if([platform isEqualToString:@"iPhone2,1"])
        return @"iPhone 3GS";
    if([platform isEqualToString:@"iPhone3,1"])
        return @"iPhone 4";
    if([platform isEqualToString:@"iPhone3,2"])
        return @"iPhone 4";
    if([platform isEqualToString:@"iPhone3,3"])
        return @"iPhone 4";
    if([platform isEqualToString:@"iPhone4,1"])
        return @"iPhone 4S";
    if([platform isEqualToString:@"iPhone5,1"])
        return @"iPhone 5";
    if([platform isEqualToString:@"iPhone5,2"])
        return @"iPhone 5";
    if([platform isEqualToString:@"iPhone5,3"])
        return @"iPhone 5c";
    if([platform isEqualToString:@"iPhone5,4"])
        return @"iPhone 5c";
    if([platform isEqualToString:@"iPhone6,1"])
        return @"iPhone 5s";
    if([platform isEqualToString:@"iPhone6,2"])
        return @"iPhone 5s";
    if([platform isEqualToString:@"iPhone7,1"])
        return @"iPhone 6 Plus";
    if([platform isEqualToString:@"iPhone7,2"])
        return @"iPhone 6";
    if([platform isEqualToString:@"iPhone8,1"])
        return @"iPhone 6s";
    if([platform isEqualToString:@"iPhone8,2"])
        return @"iPhone 6s Plus";
    if([platform isEqualToString:@"iPhone8,4"])
        return @"iPhone SE";
    if([platform isEqualToString:@"iPhone9,1"])
        return @"iPhone 7";
    if([platform isEqualToString:@"iPhone9,2"])
        return @"iPhone 7 Plus";
    if([platform isEqualToString:@"iPhone10,1"])
        return @"iPhone 8";
    if([platform isEqualToString:@"iPhone10,4"])
        return @"iPhone 8";
    if([platform isEqualToString:@"iPhone10,2"])
        return @"iPhone 8 Plus";
    if([platform isEqualToString:@"iPhone10,5"])
        return @"iPhone 8 Plus";
    if([platform isEqualToString:@"iPhone10,3"])
        return @"iPhone X";
    if([platform isEqualToString:@"iPhone10,6"])
        return @"iPhone X";
    if([platform  isEqualToString:@"iPhone11,8"])
        return @"iPhone XR";
    if([platform  isEqualToString:@"iPhone11,2"])
        return @"iPhone XS";
    if([platform  isEqualToString:@"iPhone11,4"])
        return @"iPhone XS Max";
    if([platform  isEqualToString:@"iPhone11,6"])
        return @"iPhone XS Max";
    if([platform  isEqualToString:@"iPhone12,1"])
        return @"iPhone 11";
    if ([platform isEqualToString:@"iPhone12,3"])
        return @"iPhone 11 Pro";
    if ([platform isEqualToString:@"iPhone12,5"])
        return @"iPhone 11 Pro Max";
    if ([platform isEqualToString:@"iPhone12,8"])
        return @"iPhone SE2";
    if([platform isEqualToString:@"iPod1,1"])
        return @"iPod Touch 1G";
    if([platform isEqualToString:@"iPod2,1"])
        return @"iPod Touch 2G";
    if([platform isEqualToString:@"iPod3,1"])
        return @"iPod Touch 3G";
    if([platform isEqualToString:@"iPod4,1"])
        return @"iPod Touch 4G";
    if([platform isEqualToString:@"iPod5,1"])
        return @"iPod Touch 5G";
    if([platform isEqualToString:@"iPad1,1"])
        return @"iPad 1G";
    if([platform isEqualToString:@"iPad2,1"])
        return @"iPad 2";
    if([platform isEqualToString:@"iPad2,2"])
        return @"iPad 2";
    if([platform isEqualToString:@"iPad2,3"])
        return @"iPad 2";
    if([platform isEqualToString:@"iPad2,4"])
        return @"iPad 2";
    if([platform isEqualToString:@"iPad2,5"])
        return @"iPad Mini 1G";
    if([platform isEqualToString:@"iPad2,6"])
        return @"iPad Mini 1G";
    if([platform isEqualToString:@"iPad2,7"])
        return @"iPad Mini 1G";
    if([platform isEqualToString:@"iPad3,1"])
        return @"iPad 3";
    if([platform isEqualToString:@"iPad3,2"])
        return @"iPad 3";
    if([platform isEqualToString:@"iPad3,3"])
        return @"iPad 3";
    if([platform isEqualToString:@"iPad3,4"])
        return @"iPad 4";
    if([platform isEqualToString:@"iPad3,5"])
        return @"iPad 4";
    if([platform isEqualToString:@"iPad3,6"])
        return @"iPad 4";
    if([platform isEqualToString:@"iPad4,1"])
        return @"iPad Air";
    if([platform isEqualToString:@"iPad4,2"])
        return @"iPad Air";
    if([platform isEqualToString:@"iPad4,3"])
        return @"iPad Air";
    if([platform isEqualToString:@"iPad4,4"])
        return @"iPad Mini 2G";
    if([platform isEqualToString:@"iPad4,5"])
        return @"iPad Mini 2G";
    if([platform isEqualToString:@"iPad4,6"])
        return @"iPad Mini 2G";
    if([platform isEqualToString:@"iPad4,7"])
        return @"iPad Mini 3";
    if([platform isEqualToString:@"iPad4,8"])
        return @"iPad Mini 3";
    if([platform isEqualToString:@"iPad4,9"])
        return @"iPad Mini 3";
    if([platform isEqualToString:@"iPad5,1"])
        return @"iPad Mini 4";
    if([platform isEqualToString:@"iPad5,2"])
        return @"iPad Mini 4";
    if([platform isEqualToString:@"iPad5,3"])
        return @"iPad Air 2";
    if([platform isEqualToString:@"iPad5,4"])
        return @"iPad Air 2";
    if([platform isEqualToString:@"iPad6,3"])
        return @"iPad Pro 9.7";
    if([platform isEqualToString:@"iPad6,4"])
        return @"iPad Pro 9.7";
    if([platform isEqualToString:@"iPad6,7"])
        return @"iPad Pro 12.9";
    if([platform isEqualToString:@"iPad6,8"])
        return @"iPad Pro 12.9";
    if([platform isEqualToString:@"i386"])//模拟器
        return @"iPhone模拟器";
    if([platform isEqualToString:@"x86_64"])//模拟器
        return @"iPhone模拟器";
    return platform;
}
#pragma mark 弹出举报或者反馈类似的视图
+(void)showViewController:(UIViewController *)vc
                     type:(NSInteger)type
                     data:(NSDictionary *)dic{
    ANDA_AlertVCViewController *kVC = [ANDA_AlertVCViewController sharedViewController];
    //设置ViewController的模态模式，即ViewController的显示方式
    kVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    kVC.kType = type;
    vc.modalPresentationStyle = UIModalPresentationCurrentContext;
    switch (type) {
        case 1:
            kVC.musicId = [dic objectForKey:@"musicId"];
            break;
        case 3:
            kVC.uid = [dic objectForKey:@"uid"];
            break;
        case 4:
            kVC.videoID = [dic objectForKey:@"videoID"];
            break;
        default:
            break;
    }
    [vc presentViewController:kVC animated:NO completion:nil];
}
#pragma mark - 数字转中文
+(NSString *)numberToChinese:(NSInteger )number{
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    formatter.numberStyle = kCFNumberFormatterRoundHalfDown;
    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_Hans"];
    formatter.locale = locale;
    NSString *string = [formatter stringFromNumber:[NSNumber numberWithInteger:number]];
    return string;
}
+(AppDelegate *)getCurrentAppDelegate{
    return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
static NSMutableDictionary *timers_;
dispatch_semaphore_t semaphore_;

/**
 load 与 initialize区别，这里选用initialize
 */
+(void)initialize{
    
    //GCD一次性函数
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        timers_ = [NSMutableDictionary dictionary];
        semaphore_ = dispatch_semaphore_create(1);
    });
}

+ (NSString*)timerTask:(void(^)(void))task
                 start:(NSTimeInterval) start
              interval:(NSTimeInterval) interval
               repeats:(BOOL) repeats
                 async:(BOOL)async{
    
    /**
     对参数做一些限制
     1.如果task不存在，那就没有执行的必要（!task）
     2.开始时间必须大于当前时间
     3.当需要重复执行时，重复间隔时间必须 >0
     以上条件必须满足，定时器才算是比较合理，否则没必要执行
     */
    if (!task || start < 0 || (interval <= 0 && repeats)) {
        
        return nil;
    }
    //if (!task || start < 0 || (interval <= 0 && repeats)) return nil; (上面的代码有人可能会写成这样，都一样，这是if的语法，里面只有一行时候可以省略{}，其他的没区别)
    
    /**
     队列
     asyc：YES 全局队列 dispatch_get_global_queue(0, 0) 可以简单理解为其他线程(非主线程)
     asyc：NO 主队列 dispatch_get_main_queue() 可以理解为主线程
     */
    dispatch_queue_t queue = async ? dispatch_get_global_queue(0, 0) : dispatch_get_main_queue();
    
    /**
     创建定时器 dispatch_source_t timer
     */
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
    // 定时器的唯一标识
    NSString *timerName = [NSString stringWithFormat:@"%zd", timers_.count];
    // 存放到字典中
    timers_[timerName] = timer;
    dispatch_semaphore_signal(semaphore_);
    
    dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, start * NSEC_PER_SEC), interval * NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(timer, ^{
        //定时任务
        task();
        //如果不需要重复，执行一次即可
        if (!repeats) {
            
            [YYJ_PublicClass canelTimer:timerName];
        }
    });
    //启动定时器
    dispatch_resume(timer);
    
    return timerName;
}

+ (NSString*)timerTask:(id)target
              selector:(SEL)selector
                 start:(NSTimeInterval)start
              interval:(NSTimeInterval)interval
               repeats:(BOOL)repeats
                 async:(BOOL)async{
    
    if (!target || !selector) return nil;
    
    return [self timerTask:^{
        
        if ([target respondsToSelector:selector]) {
            //（这是消除警告的处理）
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [target performSelector:selector];
#pragma clang diagnostic pop
        }
        
    } start:start interval:interval repeats:repeats async:async];
    
    

}

+(void)canelTimer:(NSString*) timerName{
    
    if (timerName.length == 0) {
        
        return;
    }
    
    dispatch_semaphore_wait(semaphore_, DISPATCH_TIME_FOREVER);
    
    dispatch_source_t timer = timers_[timerName];
    if (timer) {
        dispatch_source_cancel(timer);
        [timers_ removeObjectForKey:timerName];
    }
    
    dispatch_semaphore_signal(semaphore_);

}
#pragma mark - 获取音频时长
/** 获取音频时长 */
+ (NSTimeInterval)AudioDurationFromUrl:(NSString *)url {
    //只有这个方法获取时间是准确的 audioPlayer.duration获得的时间不准
    AVURLAsset* audioAsset = nil;
    NSDictionary *dic = @{AVURLAssetPreferPreciseDurationAndTimingKey:@(YES)};
    if ([url hasPrefix:@"http://"]||[url hasPrefix:@"https://"]) {
        audioAsset =[AVURLAsset URLAssetWithURL:[NSURL URLWithString:url] options:dic];
    }else {//播放本机录制的文件
        audioAsset =[AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:url] options:dic];
    }
    CMTime audioDuration = audioAsset.duration;
    float audioDurationSeconds =CMTimeGetSeconds(audioDuration);
    return audioDurationSeconds;
}
/// 使用此方法时请标明源作者：欧阳大哥2013。本方法符合MIT协议规范。
/// github地址：https://github.com/youngsoft
/// 计算简单文本或者属性字符串的自适应尺寸
/// @param fitsSize 指定限制的尺寸，参考UILabel中的sizeThatFits中的参数的意义。
/// @param text 要计算的简单文本NSString或者属性字符串NSAttributedString对象
/// @param numberOfLines 指定最大显示的行数，如果为0则表示不限制最大行数
/// @param font 指定计算时文本的字体，可以为nil表示使用UILabel控件的默认17号字体
/// @param textAlignment 指定文本对齐方式默认是NSTextAlignmentNatural
/// @param lineBreakMode 指定多行时断字模式，默认可以用UILabel的默认断字模式NSLineBreakByTruncatingTail
/// @param minimumScaleFactor 指定文本的最小缩放因子，默认填写0。这个参数用于那些定宽时可以自动缩小文字字体来自适应显示的场景。
/// @param shadowOffset 指定阴影的偏移位置，需要注意的是这个偏移位置是同时指定了阴影颜色和偏移位置才有效。如果不考虑阴影则请传递CGSizeZero，否则阴影会参与尺寸计算。
/// @return 返回自适应的最合适尺寸
CGSize calcTextSize(CGSize fitsSize, id text, NSInteger numberOfLines, UIFont *font, NSTextAlignment textAlignment, NSLineBreakMode lineBreakMode, CGFloat minimumScaleFactor, CGSize shadowOffset) {
    
    if (text == nil || [text length] <= 0) {
        return CGSizeZero;
    }
    
    NSAttributedString *calcAttributedString = nil;

    //如果不指定字体则用默认的字体。
    if (font == nil) {
        font = [UIFont systemFontOfSize:17];
    }
    
    CGFloat systemVersion = [UIDevice currentDevice].systemVersion.floatValue;
        
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.alignment = textAlignment;
    paragraphStyle.lineBreakMode = lineBreakMode;
    //系统大于等于11才设置行断字策略。
    if (systemVersion >= 11.0) {
        @try {
            [paragraphStyle setValue:@(1) forKey:@"lineBreakStrategy"];
        } @catch (NSException *exception) {}
    }
        
    if ([text isKindOfClass:NSString.class]) {
        calcAttributedString = [[NSAttributedString alloc] initWithString:(NSString *)text attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle}];
    } else {
        NSAttributedString *originAttributedString = (NSAttributedString *)text;
        //对于属性字符串总是加上默认的字体和段落信息。
        NSMutableAttributedString *mutableCalcAttributedString = [[NSMutableAttributedString alloc] initWithString:originAttributedString.string attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle}];
        
        //再附加上原来的属性。
        [originAttributedString enumerateAttributesInRange:NSMakeRange(0, originAttributedString.string.length) options:0 usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
            [mutableCalcAttributedString addAttributes:attrs range:range];
        }];
        
        //这里再次取段落信息，因为有可能属性字符串中就已经包含了段落信息。
        if (systemVersion >= 11.0) {
            NSParagraphStyle *alternativeParagraphStyle = [mutableCalcAttributedString attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL];
            if (alternativeParagraphStyle != nil) {
                paragraphStyle = (NSMutableParagraphStyle*)alternativeParagraphStyle;
            }
        }
        
        calcAttributedString = mutableCalcAttributedString;
    }
    
    //调整fitsSize的值, 这里的宽度调整为只要宽度小于等于0或者显示一行都不限制宽度，而高度则总是改为不限制高度。
    fitsSize.height = FLT_MAX;
    if (fitsSize.width <= 0 || numberOfLines == 1) {
        fitsSize.width = FLT_MAX;
    }
        
    //构造出一个NSStringDrawContext
    NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
    context.minimumScaleFactor = minimumScaleFactor;
    @try {
        //因为下面几个属性都是未公开的属性，所以我们用KVC的方式来实现。
        [context setValue:@(numberOfLines) forKey:@"maximumNumberOfLines"];
        if (numberOfLines != 1) {
            [context setValue:@(YES) forKey:@"wrapsForTruncationMode"];
        }
        [context setValue:@(YES) forKey:@"wantsNumberOfLineFragments"];
    } @catch (NSException *exception) {}
       

    //计算属性字符串的bounds值。
    CGRect rect = [calcAttributedString boundingRectWithSize:fitsSize options:NSStringDrawingUsesLineFragmentOrigin context:context];
    
    //需要对段落的首行缩进进行特殊处理！
    //如果只有一行则直接添加首行缩进的值，否则进行特殊处理。。
    CGFloat firstLineHeadIndent = paragraphStyle.firstLineHeadIndent;
    if (firstLineHeadIndent != 0.0 && systemVersion >= 11.0) {
        //得到绘制出来的行数
        NSInteger numberOfDrawingLines = [[context valueForKey:@"numberOfLineFragments"] integerValue];
        if (numberOfDrawingLines == 1) {
            rect.size.width += firstLineHeadIndent;
        } else {
            //取内容的行数。
            NSString *string = calcAttributedString.string;
            NSCharacterSet *charset = [NSCharacterSet newlineCharacterSet];
            NSArray *lines = [string componentsSeparatedByCharactersInSet:charset]; //得到文本内容的行数
            NSString *lastLine = lines.lastObject;
            NSInteger numberOfContentLines = lines.count - (NSInteger)(lastLine.length == 0);  //有效的内容行数要减去最后一行为空行的情况。
            if (numberOfLines == 0) {
                numberOfLines = NSIntegerMax;
            }
            if (numberOfLines > numberOfContentLines)
                numberOfLines = numberOfContentLines;
            
            //只有绘制的行数和指定的行数相等时才添加上首行缩进！这段代码根据反汇编来实现，但是不理解为什么相等才设置？
            if (numberOfDrawingLines == numberOfLines) {
                rect.size.width += firstLineHeadIndent;
            }
        }
    }
    
    //取fitsSize和rect中的最小宽度值。
    if (rect.size.width > fitsSize.width) {
        rect.size.width = fitsSize.width;
    }
    
    //加上阴影的偏移
    rect.size.width += fabs(shadowOffset.width);
    rect.size.height += fabs(shadowOffset.height);
       
    //转化为可以有效显示的逻辑点, 这里将原始逻辑点乘以缩放比例得到物理像素点，然后再取整，然后再除以缩放比例得到可以有效显示的逻辑点。
    CGFloat scale = [UIScreen mainScreen].scale;
    rect.size.width = ceil(rect.size.width * scale) / scale;
    rect.size.height = ceil(rect.size.height *scale) / scale;
    
    return rect.size;
}

//上述方法的精简版本
NS_INLINE CGSize calcTextSizeV2(CGSize fitsSize, id text, NSInteger numberOfLines, UIFont *font) {
    return calcTextSize(fitsSize, text, numberOfLines, font, NSTextAlignmentNatural, NSLineBreakByTruncatingTail,0.0, CGSizeZero);
}
#pragma mark - 弹出自定义文字显示弹窗
/// 弹出自定义文字显示弹窗
/// @param msg 文字内容
/// @param vc 依赖界面
+(void)showPopUpsVC:(NSString *)msg toVC:(UIViewController *)vc{
    ANDA_PopUpsViewController *kVC = [ANDA_PopUpsViewController sharedViewController];
    kVC.kInfo = msg;
    //设置ViewController的模态模式，即ViewController的显示方式
    kVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    vc.modalPresentationStyle = UIModalPresentationCurrentContext;
    [vc presentViewController:kVC animated:NO completion:^{
        
    }];
}
#pragma mark - 弹出分享页面
/// 弹出分享页面
/// @param state 需要什么类型
/// @param vc 依赖界面
+(void)show_sharePage_vc:(SharePage_Class)state
                    toVC:(UIViewController *)vc
                  choice:(nonnull void (^)(SharePage_Class))choice{
    if ([vc isKindOfClass:[UIView class]]) {
        vc = [YYJ_PublicClass getCurrentVC];
    }
    ANDA_SharePage_ViewController *kVC = [ANDA_SharePage_ViewController sharedViewController];
    kVC.state = state;
    kVC.choice_block = choice;
    //设置ViewController的模态模式，即ViewController的显示方式
    kVC.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    vc.modalPresentationStyle = UIModalPresentationCurrentContext;
    [vc presentViewController:kVC animated:YES completion:^{
        
    }];
}

+(void)getprotocolObj:(NSString *)type
                toUrl:(void (^)(NSString *url))url_back{
    YYJ_PublicWebViewController *kVC = [YYJ_PublicWebViewController NewPublicWebViewController];
    kVC.urlString = [APPHost stringByAppendingFormat:@"/getprotocol?type=%@&language=%@",type,[YYJ_UserProfileModel sharedUserProfile].language];
    
//            QLPreviewController *kVC = [QLPreviewController new];
//            kVC.dataSource = self;
//            kVC.delegate = self;
//            //跳转到打开world文档页面
    [[YYJ_PublicClass getCurrentVC].navigationController pushViewController:kVC animated:YES];
}
#pragma mark - 将所有字段转化为一个字符 计算字符串长度
+ (NSString *)getStringLengthWithString:(NSString *)string andIntString:(int)number
{
    __block NSInteger stringLength = 0;
    __block NSString *returnString = @"";
    [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop)
     {
         stringLength++;
         if(stringLength>number){
             
         }else{
             returnString = [returnString stringByAppendingString:substring];
         }
     }];
    return returnString;
}
/// 获取全屏照片 格式为 XXX_(宽x高)
+(UIImage *)getFullCcreenImage:(NSString *)name{
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    
    CGFloat scale = [UIScreen mainScreen].scale;
    NSString *image_name = [NSString stringWithFormat:@"%@_(%.0fx%.0f)",name,screenSize.width*scale,screenSize.height*scale];
    return [UIImage imageNamed:image_name];
}
/// 获取全屏照片名字 格式为 XXX_(宽x高)
+(NSString *)getFullCcreenImageName:(NSString *)name{
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    
    CGFloat scale = [UIScreen mainScreen].scale;
    NSString *image_name = [NSString stringWithFormat:@"%@_(%.0fx%.0f)",name,screenSize.width*scale,screenSize.height*scale];
    return image_name;
}
@end
